package com.spa.infrastructure.service.douyin;

import cn.hutool.json.JSONUtil;
import com.spa.infrastructure.service.douyin.param.CreateOrderParam;
import com.spa.infrastructure.service.douyin.param.JsCode2SessionParam;
import com.spa.infrastructure.service.douyin.result.CreateOrderResult;
import com.spa.infrastructure.service.douyin.result.GetPhoneResult;
import com.spa.infrastructure.service.douyin.result.JsCode2SessionResult;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.Base64;
import java.util.HashMap;
import java.util.Map;

@Service
@Slf4j
public class DouYinMiNiService extends DouYinService{

    @Value("${douYin.mini.secret}")
    private String secret;

    @Value("${douYin.mini.appId}")
    private String appId;

    @Value("${domain}")
    private String myDomain;

    @Autowired
    private Sign sign;

    public JsCode2SessionResult login(String code, String anonymous_code) {
        String domain = DouYinConstant.DOMAIN;
        JsCode2SessionParam param = JsCode2SessionParam.builder()
                .anonymous_code(anonymous_code)
                .appid(appId)
                .code(code)
                .secret(secret)
                .build();
        String result = sendPost4DouYin(domain, DouYinConstant.CODE2SESSION, JSONUtil.toJsonStr(param));
        JsCode2SessionResult sessionResult = JSONUtil.toBean(result, JsCode2SessionResult.class);
        log.info("JsCode2SessionResult : {}", sessionResult);
        return sessionResult;
    }

    public CreateOrderResult createOrder(String orderCode) {
        String notifyUrl = myDomain + DouYinConstant.NOTIFY_URL;
        Map<String, Object> paramsMap = new HashMap<>();
        paramsMap.put("app_id", appId);
        paramsMap.put("out_order_no", orderCode);
        paramsMap.put("total_amount", 1);
        paramsMap.put("subject", "浴悦来了");
        paramsMap.put("body", "浴悦到家平台服务");
        paramsMap.put("valid_time", 500);
        paramsMap.put("notify_url", notifyUrl);
        String sign0 = sign.requestSign(paramsMap);
        CreateOrderParam param = CreateOrderParam.builder()
                .app_id(appId)
                .out_order_no(orderCode)
                .total_amount(1)
                .subject("浴悦来了")
                .body("浴悦到家平台服务")
                .valid_time(500)
                .sign(sign0)
                .notify_url(notifyUrl)
                .build();
        String result = sendPost4DouYin(DouYinConstant.DOMAIN, DouYinConstant.CREATE_ORDER, JSONUtil.toJsonStr(param));
        CreateOrderResult createOrderResult = JSONUtil.toBean(result, CreateOrderResult.class);
        log.info("CreateOrderResult : {}", createOrderResult);
        return createOrderResult;
    }

    /**
     * Java 不支持 PKCS7Padding，只支持 PKCS5Padding，虽然名字不同，但是算法相同。
     * @param encryptedData
     * @param sessionKey
     * @param iv
     * @return
     * @throws NoSuchPaddingException
     * @throws NoSuchAlgorithmException
     * @throws InvalidAlgorithmParameterException
     * @throws InvalidKeyException
     * @throws BadPaddingException
     * @throws IllegalBlockSizeException
     */
    public GetPhoneResult decrypt(String encryptedData, String sessionKey, String iv) throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidAlgorithmParameterException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException {
        Base64.Decoder decoder = Base64.getDecoder();
        byte[] sessionKeyBytes = decoder.decode(sessionKey);
        byte[] ivBytes = decoder.decode(iv);
        byte[] encryptedBytes = decoder.decode(encryptedData);

        Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
        SecretKeySpec skeySpec = new SecretKeySpec(sessionKeyBytes, "AES");
        IvParameterSpec ivSpec = new IvParameterSpec(ivBytes);
        cipher.init(Cipher.DECRYPT_MODE, skeySpec, ivSpec);
        byte[] ret = cipher.doFinal(encryptedBytes);
        GetPhoneResult getPhoneResult = JSONUtil.toBean(new String(ret), GetPhoneResult.class);
        log.info("GetPhoneResult : {}", getPhoneResult);
        return getPhoneResult;
    }

}
